package com.mugui.base.client.net.bagsend;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import cn.hutool.http.ContentType;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONObject;
import com.mugui.sql.SqlServer;
import lombok.Getter;
import okhttp3.*;
import okio.BufferedSink;
import org.apache.commons.lang3.StringUtils;

import com.mugui.base.base.Autowired;
import com.mugui.base.base.Component;
import com.mugui.base.client.net.baghandle.NetHandle;
import com.mugui.base.client.net.bean.Message;
import com.mugui.base.client.net.bean.NetBag;
import com.mugui.base.util.Other;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.RandomUtil;

@Component
public class BagSend {
    private String server;

    @Autowired
    private NetHandle netHandle;

    private String session;

    private String setSession(String session) {
//        SharedPreferences mugui = DataSave.app.getBaseContext().getSharedPreferences("mugui", Context.MODE_PRIVATE);
//        mugui.edit().putString("session", session).commit();
        return this.session = session;
    }

    private String getSession() {
//        SharedPreferences mugui = DataSave.app.getBaseContext().getSharedPreferences("mugui", Context.MODE_PRIVATE);
//        String session = mugui.getString("session", null);
//        return session;
        return session;
    }

    private HashMap<String, String> sessionhead = new HashMap<>();


    private static AtomicInteger atomicInteger=new AtomicInteger(0);

    public static boolean isRunningBag(){
        return atomicInteger.get()>0;
    }


    @Getter
    private String http_server;
    @Getter
    private String ws_server;

    public void init() {
        if (server.startsWith("http")) {
            if (!server.endsWith("/")) {
                server = server + "/";
            }
            http_server = server;
            ws_server = server.replace("http", "ws");
            return;
        }
        if (server.startsWith("ws")) {
            if (!server.endsWith("/")) {
                server = server + "/";
            }
            ws_server = server;
            http_server = server.replace("ws", "http");
            return;
        }
        http_server = "http://" + server + "/";
        ws_server = "ws://" + server + "/";
    }

    public void setServerUrl(String url) {
        server = url;
        init();
    }

    @Autowired
    private BagSendTask bagSendTask;


    /**
     * 优先级
     */
    @Getter
    private static ThreadLocal<Integer> priority = new ThreadLocal<>();


    public NetCall sendBag(NetBag bag, File... file) {

        String name = Thread.currentThread().getName();
        NetCall netCall = new NetCall(bag.getFunc());
        bagSendTask.addTask(new Runnable() {
            @Override
            public void run() {
                atomicInteger.incrementAndGet();
                Thread.currentThread().setName(name + ":sendBag");
                bag.setHash(Other.MD5(bag.toString() + System.currentTimeMillis() + RandomUtil.randomInt()));
                bag.setSession(getSession());
                String post = null;
                try {
                    System.out.println("请求数据: " + http_server + "->" + bag);
                    if (file.length > 0) {
                        post = HTTPUtil.post(http_server, sessionhead, bag.toJson(), file);
                    } else {
                        post = HTTPUtil.post(http_server, sessionhead, bag.toString());
                    }
                    System.out.println("返回数据: " + post);
                    if (post == null) {
                        throw new RuntimeException(http_server + " bag:" + bag + "访问错误");
                    }
                } catch (Exception e) {
                    Message message = new Message();
                    message.setDate(e.getMessage());
                    message.setMsg("服务器出错了");
                    message.setType(500);
                    bag.setData(message);
                    post = bag.toString();
                }
                NetBag bag2 = NetBag.newBean(NetBag.class, post);
                if (StringUtils.isNotBlank(bag2.getSession()))
                    sessionhead.put("Cookie", "SESSION=" + (setSession(Base64.encode(bag2.getSession()))) + "");
                System.out.println("处理结果: " + netHandle.httpHandle(bag2, netCall));
                atomicInteger.decrementAndGet();
            }
        }, priority.get());
        return netCall;
    }

    public NetCall sendData(String func) {
        return sendData(func, null);
    }

    public NetCall sendData(String func, Object data) {
        NetBag bag = new NetBag();
        bag.setFunc(func).setData(data);
        return sendBag(bag);
    }

    public NetCall sendData(String func, Object data, File file) {
        NetBag bag = new NetBag();
        bag.setFunc(func).setData(data);
        return sendBag(bag, file);
    }


    public NetCall post(String api) {
        return post(api, null);
    }

    public NetCall post(String api, JSONObject data) {
        String name = Thread.currentThread().getName();
        NetCall netCall = new NetCall(api);
        bagSendTask.addTask(new Runnable() {
            @Override
            public void run() {
                Thread.currentThread().setName(name + ":post");
                try {
                    handlePost(netCall, data);
                } finally {
                    try {
                        SqlServer.reback();
                    } catch (Throwable e) {
                    }
                }
            }
        }, priority.get());
        return netCall;
    }

    private void handlePost(NetCall netCall, JSONObject data) {
        atomicInteger.incrementAndGet();
        NetBag bag = new NetBag();
        bag.setFunc(netCall.getFunc());
        bag.setData(data);
        bag.setHash(Other.MD5(bag.toString()));

        bag.setSession(netCall.getId());
        try {

            System.out.println("请求数据: " + http_server + "->" + data);

            String post = HTTPUtil.post(http_server + bag.getFunc(), sessionhead, bag.getData().toString());
            if (post == null) {
                throw new RuntimeException(http_server + " bag:" + bag + "访问错误");
            }
            System.out.println("返回数据: " + post);
            bag.setData(Message.ok(post));
            if (StringUtils.isNotBlank(bag.getSession()))
                sessionhead.put("Cookie", "SESSION=" + (setSession(Base64.encode(bag.getSession()))) + "");
            System.out.println("处理结果: " + netHandle.httpHandle(bag, netCall));
        } catch (Exception e) {
            e.printStackTrace();
            NetCall.Call son = netCall.getSon();
            if (son != null) {
                son.err(new Message().setDate(e.getMessage()).setMsg("服务器出错了" + e.getMessage()).setType(500));
            }
            NetCall.Call main = netCall.getMain();
            if (main != null) {
                main.err(new Message().setDate(e.getMessage()).setMsg("服务器出错了" + e.getMessage()).setType(500));
            }
        }
        atomicInteger.decrementAndGet();
    }


    public void postWait(NetCall netCall) {
        postWait(netCall, null);
    }

    public void postWait(NetCall netCall, JSONObject o) {
        handlePost(netCall, o);
    }


    public NetCall subWs(String func, Object data) {
        NetCall netCall = WSUtil.subNetCall(func);
        ws("sub." + func, data, netCall);
        return netCall;

    }

    public NetCall subWs(String func) {
        return subWs(func, null);
    }

    public void unsubWs(NetCall netCall) {
        WSUtil.unsubNetCall(netCall.getId());
        ws("unsub." + netCall.getFunc(), null, netCall);
    }

    @Autowired
    private WsHandle wsHandle;

    @Autowired
    private WsOutTimeTask wsOutTimeTask;

    private void ws(String type_func, Object data, NetCall netCall) {

        String name = Thread.currentThread().getName();
        bagSendTask.addTask(new Runnable() {
            @Override
            public void run() {
                atomicInteger.incrementAndGet();
                Thread.currentThread().setName(name + ":ws");
                NetBag bag = new NetBag();
                bag.setFunc(type_func);
                bag.setData(data);
                bag.setHash(Other.MD5(bag.toString()));
                bag.setSession(netCall.getId());
                try {

                    System.out.println("请求数据: " + http_server + " " + netCall.getId() + " " + type_func);
                    WSUtil.ws(ws_server, sessionhead, bag, wsHandle);
                    NetCall wsNetCall = WSUtil.getWsNetCall(netCall.getId());
                    wsNetCall.setThreadName(name + ":ws:net");
                    wsOutTimeTask.add(wsNetCall);
                } catch (Exception e) {
                    e.printStackTrace();
                    NetCall wsNetCall = WSUtil.getWsNetCall(netCall.getId());
                    wsOutTimeTask.del(wsNetCall);
                    NetCall.Call son = wsNetCall.getSon();
                    if (son != null) {
                        son.err(new Message().setDate(e.getMessage()).setMsg("服务器出错了" + e.getMessage()).setType(500));
                    }
                    NetCall.Call main = wsNetCall.getMain();
                    if (main != null) {
                        main.err(new Message().setDate(e.getMessage()).setMsg("服务器出错了" + e.getMessage()).setType(500));
                    }
                } finally {
                    try {
                        SqlServer.reback();
                    } catch (Throwable e) {
                    }
                    atomicInteger.decrementAndGet();
                }
            }
        }, priority.get());
    }

    public void waitPostFromData(NetCall netCall, HashMap<String, Object> data) {
        atomicInteger.incrementAndGet();
        NetBag bag = new NetBag();
        bag.setFunc(netCall.getFunc());
        bag.setData(data);
        bag.setHash(Other.MD5(bag.toString()));

        bag.setSession(netCall.getId());
        try {

            System.out.println("请求数据: " + http_server + "->" + bag);

            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.connectTimeout((int) HTTPUtil.getOutTime(), java.util.concurrent.TimeUnit.SECONDS);
            builder.readTimeout((int) HTTPUtil.getOutTime(), java.util.concurrent.TimeUnit.SECONDS);
            builder.writeTimeout((int) HTTPUtil.getOutTime(), java.util.concurrent.TimeUnit.SECONDS);
            OkHttpClient build = builder.followRedirects(true).build();
            MultipartBody.Builder multipartBuilder = new MultipartBody.Builder()
                    .setType(MultipartBody.FORM);

            for (Map.Entry<String, Object> entry : data.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                if (value instanceof File) {
                    File file = (File) value;
                    // 根据实际情况设置文件的 media type，比如 "image/jpeg"、"application/octet-stream" 等
                    RequestBody fileBody = RequestBody.create(file, MediaType.parse("application/octet-stream"));
                    multipartBuilder.addFormDataPart(key, file.getName(), fileBody);
                } else {
                    multipartBuilder.addFormDataPart(key, value.toString());
                }
            }
            RequestBody requestBody = multipartBuilder.build();
            // 构造请求，注意 cookie 的设置
            Request request = new Request.Builder()
                    .url(http_server + bag.getFunc())
                    .post(requestBody)
                    .header("Cookie", "SESSION=" + setSession(Base64.encode(bag.getSession())))
                    .build();

            okhttp3.Response response = build.newCall(request).execute();
            String post = response.body().string();
            if (post == null) {
                throw new RuntimeException(http_server + " bag:" + bag + "访问错误");
            }
            System.out.println("返回数据: " + post);
            Message ok = Message.ok(post);
            if (StringUtils.isNotBlank(bag.getSession()))
                sessionhead.put("Cookie", "SESSION=" + (setSession(Base64.encode(bag.getSession()))) + "");
            NetCall.Call son = netCall.getSon();
            if (son != null) {
                son.ok(ok);
            }
            NetCall.Call main = netCall.getMain();
            if (main != null) {
                main.ok(ok);
            }
        } catch (Exception e) {
            e.printStackTrace();
            NetCall.Call son = netCall.getSon();
            if (son != null) {
                son.err(new Message().setDate(e.getMessage()).setMsg("服务器出错了" + e.getMessage()).setType(500));
            }
            NetCall.Call main = netCall.getMain();
            if (main != null) {
                main.err(new Message().setDate(e.getMessage()).setMsg("服务器出错了" + e.getMessage()).setType(500));
            }
        }
        atomicInteger.decrementAndGet();
    }


    public void waitGet(NetCall netCall) {
        atomicInteger.incrementAndGet();
        NetBag bag = new NetBag();
        bag.setFunc(netCall.getFunc());
        bag.setHash(Other.MD5(bag.toString()));

        bag.setSession(netCall.getId());
        try {

            System.out.println("请求数据: " + http_server + "->" + bag);

            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.connectTimeout((int) HTTPUtil.getOutTime(), java.util.concurrent.TimeUnit.SECONDS);
            builder.readTimeout((int) HTTPUtil.getOutTime(), java.util.concurrent.TimeUnit.SECONDS);
            builder.writeTimeout((int) HTTPUtil.getOutTime(), java.util.concurrent.TimeUnit.SECONDS);
            OkHttpClient build = builder.followRedirects(true).build();
            Request request = new Request.Builder()
                    .url(http_server + bag.getFunc())
                    .get()
                    .header("Cookie", "SESSION=" + setSession(Base64.encode(bag.getSession())))
                    .build();
            okhttp3.Response response = build.newCall(request).execute();
            String post = response.body().string();
            if (post == null) {
                throw new RuntimeException(http_server + " bag:" + bag + "访问错误");
            }
            System.out.println("返回数据: " + post);
            Message ok = Message.ok(post);
            if (StringUtils.isNotBlank(bag.getSession()))
                sessionhead.put("Cookie", "SESSION=" + (setSession(Base64.encode(bag.getSession()))) + "");
            NetCall.Call son = netCall.getSon();
            if (son != null) {
                son.ok(ok);
            }
            NetCall.Call main = netCall.getMain();
            if (main != null) {
                main.ok(ok);
            }
        } catch (Exception e) {
            e.printStackTrace();
            NetCall.Call son = netCall.getSon();
            if (son != null) {
                son.err(new Message().setDate(e.getMessage()).setMsg("服务器出错了" + e.getMessage()).setType(500));
            }
            NetCall.Call main = netCall.getMain();
            if (main != null) {
                main.err(new Message().setDate(e.getMessage()).setMsg("服务器出错了" + e.getMessage()).setType(500));
            }
        }
        atomicInteger.decrementAndGet();
    }


}
